// Copyright (c) 2009, Philip Tucker
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the <organization> nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY Philip Tucker 'AS IS' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL Philip Tucker BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package edu.luc.android;

import java.util.ArrayList;
import java.util.HashMap;

import android.graphics.drawable.Drawable;
import android.util.Log;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.OverlayItem;

public abstract class MyItemizedOverlay extends
    ItemizedOverlay<OverlayItem> {
  private static final String LOG_ID =
      MyItemizedOverlay.class.getSimpleName();

  private final ArrayList<OverlayItem> items = new ArrayList<OverlayItem>();

  private final HashMap<String, OverlayItem> itemsById =
      new HashMap<String, OverlayItem>();

  public MyItemizedOverlay(Drawable defaultMarker) {
    super(boundCenterBottom(defaultMarker));
    populate();
  }

  @Override
  protected synchronized OverlayItem createItem(int i) {
    Log.v(LOG_ID, "createItem: " + i);
    return items.get(i);
  }

  @Override
  public synchronized int size() {
    int result = items.size();
    return result;
  }

  /**
   * Remove all items.
   */
  public synchronized void clear() {
    Log.v(LOG_ID, "clear");
    items.clear();
    itemsById.clear();
    populate();
  }

  /**
   * @return True iff we have no items.
   */
  public synchronized boolean isEmpty() {
    return items.isEmpty();
  }

  /**
   * @see MyItemizedOverlay#add(GeoPoint, String, String, Drawable)
   */
  public OverlayItem add(GeoPoint point) {
    return add(point, null, null, null);
  }

  /**
   * @see MyItemizedOverlay#add(GeoPoint, String, String, Drawable)
   */
  public OverlayItem add(GeoPoint point, String title, String snippet) {
    return add(point, title, snippet, null);
  }

  /**
   * @param point Geo point.
   * @return True iff we already have an overlay item for this point.
   */
  public synchronized boolean contains(GeoPoint point) {
    String latLonE6String = Geo.toLatLonE6String(point);
    return itemsById.containsKey(latLonE6String);
  }

  /**
   * Add a new item at current position in circular list. If item already
   * exists, select and return it.
   * 
   * @param point Point at which item should be added.
   * @param title Marker title.
   * @param snippet Marker snippet (ie, description).
   * @param marker If null use default, otherwise use this marker.
   * @return Newly added item.
   */
  public synchronized OverlayItem add(GeoPoint point, String title, 
      String snippet, Drawable marker) {
    if (contains(point)) {
      Log.v(LOG_ID, "already have " + point);
      return null;
    }
    
    String latLonE6String = Geo.toLatLonE6String(point);
    Log.v(LOG_ID, "adding " + latLonE6String);
    if (title == null) {
      title = latLonE6String;
    }
    if (snippet == null) {
      snippet = "I am #" + title + ".";
    }
    OverlayItem result = new OverlayItem(point, title, snippet);
    if (marker != null) {
      result.setMarker(boundCenterBottom(marker));
    }
    items.add(result);
    itemsById.put(latLonE6String, result);
    populate();

    return result;
  }

  @Override
  protected synchronized boolean onTap(int index) {
    Log.v(LOG_ID, "onTap " + index);
    onItemSelected(items.get(index));
    return true;
  }

  protected abstract void onItemSelected(OverlayItem item);
}
